_version_code = "0.1.2.3"

import pygame
import math
import os.path
import heapq

# 初始化pygame
pygame.init()

# 颜色定义
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
YELLOW = (255, 255, 0)
BLUE = (0, 0, 255)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
GRAY = (128, 128, 128)
GOLD = (255, 215, 0)
ORANGE = (255, 165, 0)

# 六边形参数
HEX_RADIUS = 25
HEX_WIDTH = HEX_RADIUS * 2
HEX_HEIGHT = math.sqrt(3) * HEX_RADIUS
HEX_VERTICES = 6

ADJACENT_HEXAGONS = [(1, 0), (1, -1), (0, -1), (-1, 0), (-1, 1), (0, 1)]
LANCER_ATTACK = ADJACENT_HEXAGONS+[(2, 0), (2, -2), (0, -2), (-2, 0), (-2, 2), (0, 2)]
RIDER_ATTACK = ADJACENT_HEXAGONS+[(1, 1), (2, -1), (1, -2), (-1, -1), (-2, 1), (-1, 2)]
a = [(3-i, i) for i in range(3)]
b = [(-i, 3) for i in range(3)]
c = [(-3, 3-i) for i in range(3)]
d = a+b+c
DRUID_VISION = ADJACENT_HEXAGONS+d+[(-i[0], -i[1]) for i in d]
a = [(4-i, i) for i in range(4)]
b = [(-i, 4) for i in range(4)]
c = [(-4, 4-i) for i in range(4)]
d = a+b+c
DRUID_VISION += d+[(-i[0], -i[1]) for i in d]

# chess info: ca(counterattack): 0-no attack 1-close attack 2-ranged attack  atk_obj: 0-blank 1-enemy 2-comrade
PIECE_TYPES = [
    {"id": 0, "name": "Master", "hp": 3, "atk": 0, "vis": 1, "atk_r": ADJACENT_HEXAGONS, "mp": 1, "cost": 12, "icon_path": "master_icon.png", "ca": 0, 'atk_obj': 0},
    {"id": 1, "name": "Saber", "hp": 9, "atk": 4, "vis": 2, "atk_r": ADJACENT_HEXAGONS, "mp": 3, "cost": 3, "icon_path": "saber_icon.png", "ca": 1, 'atk_obj': 1},
    {"id": 2, "name": "Archer", "hp": 6, "atk": 2, "vis": 2, "atk_r": 2, "mp": 3, "cost": 3, "icon_path": "archer_icon.png", "ca": 2, 'atk_obj': 1},
    {"id": 3, "name": "Lancer", "hp": 8, "atk": 3, "vis": 2, "atk_r": LANCER_ATTACK, "mp": 2, "cost": 3, "icon_path": "lancer_icon.png", "ca": 1, 'atk_obj': 1},
    {"id": 4, "name": "Caster", "hp": 6, "atk": 6, "vis": 2, "atk_r": 2, "mp": 2, "cost": 4, "icon_path": "caster_icon.png", "ca": 2, 'atk_obj': 1},
    {"id": 5, "name": "Rider", "hp": 8, "atk": 4, "vis": 2, "atk_r": RIDER_ATTACK, "mp": 5, "cost": 4, "icon_path": "knight_icon.png", "ca": 1, 'atk_obj': 1},
    {"id": 6, "name": "Assassin", "hp": 4, "atk": 7, "vis": 1, "atk_r": ADJACENT_HEXAGONS, "mp": 4, "cost": 5, "icon_path": "assassin_icon.png", "ca": 1, 'atk_obj': 1},
    {"id": 7, "name": "Priest", "hp": 6, "atk": -2, "vis": 2, "atk_r": 2, "mp": 3, "cost": 3, "icon_path": "priest_icon.png", "ca": 0, 'atk_obj': 2},
    {"id": 8, "name": "Druid", "hp": 6, "atk": 6, "vis": DRUID_VISION, "atk_r": (3, 4), "mp": 2, "cost": 5, "icon_path": "druid_icon.png", "ca": 2, 'atk_obj': 1},
    {"id": 9, "name": "Sheilder", "hp": 10, "atk": 2, "vis": 1, "atk_r": ADJACENT_HEXAGONS, "mp": 2, "cost": 6, "icon_path": "guard_icon.png", "ca": 1, 'atk_obj': 2}
]

# 地图尺寸
MAP_ROWS = 20
MAP_COLS = 20

# 根据地图尺寸动态调整屏幕尺寸
SCREEN_WIDTH = int(HEX_RADIUS * math.sqrt(3) * (MAP_COLS + 1)) + 300  # 地图宽度 + 提示区宽度
SCREEN_HEIGHT = int(HEX_RADIUS * 3/2 * (MAP_ROWS + 1))  # 地图高度
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption("ChessPlus")

class Hexagon:
    def __init__(self, col, row):
        self.col = col
        self.row = row
        self.center = self.get_center()
        self.vertices = self.get_vertices()
        # self.is_selected = False
        self.is_moveable = False
        self.is_attackable = False
        self.is_highlighted = False

    def get_center(self):
        """计算六边形的中心点坐标，符合斜坐标系"""
        x = HEX_RADIUS * math.sqrt(3) * (self.col + 0.5 * self.row)
        y = HEX_RADIUS * 3/2 * self.row
        return x, y

    def get_vertices(self):
        """计算六边形的顶点坐标"""
        vertices = []
        for i in range(HEX_VERTICES):
            angle = math.pi / 3 * (i + 0.5)  # 调整角度以适应 pointy top
            x = self.center[0] + HEX_RADIUS * math.cos(angle)
            y = self.center[1] + HEX_RADIUS * math.sin(angle)
            vertices.append((x, y))
        return vertices

    def heuristic(a, b):
        """启发式函数，从 a 到 b 的直线距离"""
        delta_row = a.row - b.row
        delta_col = a.col - b.col
        if delta_row * delta_col > 0:
            return abs(delta_row + delta_col)
        else:
            return (abs(delta_row + delta_col) + abs(delta_row - delta_col)) // 2
            
    def straight_distance_to(self, other_hexagon):
        """计算两个六边形之间的距离"""
        return self.heuristic(other_hexagon)

    def __lt__(self, other):
        """实现小于比较操作符，通过比较 col 和 row 属性"""
        return (self.col, self.row) < (other.col, other.row)

class Piece:
    def __init__(self, id, player):
        self.piece_id = None
        self.type_id = id
        self.ca = PIECE_TYPES[id]["ca"]
        self.name = PIECE_TYPES[id]["name"]
        self.hp = PIECE_TYPES[id]["hp"]
        self.atk = PIECE_TYPES[id]["atk"]
        self.atk_r = PIECE_TYPES[id]["atk_r"]
        self.mp = PIECE_TYPES[id]["mp"]
        self.cost = PIECE_TYPES[id]["cost"]
        self.atk_obj = PIECE_TYPES[id]["atk_obj"]
        self.vis = PIECE_TYPES[id]["vis"]
        self.buff = 0
        self.show_to_enemy = False if self.name == "Assassin" else True
        icon_path = PIECE_TYPES[id]["icon_path"]
        self.icon = pygame.image.load(os.path.join(os.path.dirname(__file__), 'icons', icon_path)).convert_alpha()
        # 缩放图标以适应六边形网格
        icon_size = int(HEX_RADIUS * 1.8)
        self.icon = pygame.transform.scale(self.icon, (icon_size, icon_size))
        self.player = player
        self.position = None
        self.is_guarded = False  # 是否被守护，一个大回合生效

    def move(self, hexagon, distance_to):
        """移动棋子到指定的六边形"""
        if self.mp > 0:
            self.mp -= distance_to(self.position, hexagon)
            self.position = hexagon

    def attack(self, target):
        """攻击目标棋子"""
        # 攻击显形
        self.show_to_enemy = True
        beat_master = False
        if self.name == "Sheilder":
            target.is_guarded = True
        elif target.name == "Master":
            target.hp -= 1  # Master 受到的所有伤害固定为 1
            target.player.cost += 1
        else:
            target.hp -= self.atk + self.buff
            # counterattack
            if self.name == 'Lancer' and self.position.straight_distance_to(target.position) == 2:
                if target.ca == 1:
                    self.hp -= target.atk - 2
            elif self.ca == 1:
                if target.ca == 1:
                    self.hp -= target.atk-1
                elif target.ca == 2:
                    self.hp -= 1
            elif self.ca == 2 and target.ca == 2:
                self.hp -= target.atk-1
        if target.hp <= 0:
            target.player.pieces.remove(target)
            if target.name == "Master":
                beat_master = True
        if self.hp <= 0:
            try:
                self.player.pieces.remove(self)
            except:
                pass
        elif target.hp > PIECE_TYPES[target.type_id]["hp"]:
            target.hp = PIECE_TYPES[target.type_id]["hp"]  # 防止血量超过最大值
        self.mp = 0
        return beat_master

class Player:
    def __init__(self, id, color):
        self.id = id
        self.color = color
        # 初始化 Master 棋子
        self.master = Piece(0, self)
        self.pieces = [self.master]  # 初始化玩家拥有的棋子列表
        self.cost = 5  # 初始化 cost

    def add_piece(self, type_id, hexagon):
        """添加一个新的棋子到指定的六边形"""
        piece = Piece(type_id, self)
        piece.position = hexagon
        self.pieces.append(piece)
        self.cost -= piece.cost

class Game:
    def __init__(self):
        self.font = pygame.font.Font(None, 36)
        self.players = [Player(1, WHITE), Player(2, BLACK)]  # 初始化玩家列表，创建两个玩家对象
        self.current_player = self.players[0]
        self.map = self.create_map()
        self.selected_piece = None
        self.selected_piece_to_place = None  # piece_data["id"]
        self.turn_number = 1
        self.ok_to_draw_psm = False  # 是否允许绘制 Piece Selection Menu
        self.piece_box_height = 60  # 每个棋子的方格高度
        # 创建地图和提示区的 Surface 对象
        self.map_surface = pygame.Surface((SCREEN_WIDTH - 400, SCREEN_HEIGHT))  # 地图区域
        self.info_surface = pygame.Surface((400, SCREEN_HEIGHT))  # 提示区域
        # 设置提示区的背景颜色
        self.info_surface.fill(WHITE)
        self.game_over = False  # 添加游戏结束标志
        self.show_start_screen = True  # 添加开始界面标志
        self.start_button_pressed = False  # 添加按键按下标志
        self.next_turn_button_pressed = False  # 添加按键按下标志
        self.show_fog_of_war = True  # 初始状态为 True，按钮颜色为蓝色
        self.map_offset_x = -500  # 地图的X轴偏移量
        self.map_offset_y = 0  # 地图的Y轴偏移量
        self.map_scale = 1.0  # 地图的缩放比例
        self.dragging = False  # 是否正在拖动地图
        self.drag_start_pos = (0, 0)  # 拖动起始位置

    def create_map(self):
        """创建游戏地图"""
        map = {}
        # 绘制指定数量的六边形棋盘
        for row in range(23):
            for col in range(33):
                hexagon = Hexagon(col, row)
                map[(col, row)] = hexagon
        # Notice: 手动设置Master位置
        self.players[0].master.position = map[(19, 5)]
        self.players[1].master.position = map[(13, 17)]
        return map
    
    def distance_to(self, hex1, hex2):
        if hex1 == hex2:
            return 0
        open_set = [(0, hex1)]
        heapq.heapify(open_set)  # 将列表转换为堆
        closed_set = set()
        came_from = {}
        g_score = {hex1: 0}
        f_score = {hex1: Hexagon.heuristic(hex1, hex2)}
        # Notice: 循环结构嵌套，效率较低
        while open_set:
            current = heapq.heappop(open_set)[1]
            if current == hex2:
                path = []
                while current in came_from:
                    path.append(current)
                    current = came_from[current]
                return len(path)
            closed_set.add(current)
            for delta_col, delta_row in ADJACENT_HEXAGONS:
                col = current.col + delta_col
                row = current.row + delta_row
                if (col, row) in self.map:
                    neighbor = self.map[(col, row)]
                    if not self.get_piece_at(neighbor) and neighbor not in closed_set:
                        tentative_g_score = g_score[current] + 1
                        if neighbor not in g_score or tentative_g_score < g_score[neighbor]:
                            came_from[neighbor] = current
                            g_score[neighbor] = tentative_g_score
                            f_score[neighbor] = tentative_g_score + Hexagon.heuristic(neighbor, hex2)
                            heapq.heappush(open_set, (f_score[neighbor], neighbor))

        return float('inf')  # 如果无法到达目标，返回无穷大

    def draw(self, screen):
        """绘制游戏界面"""
        # 清空地图和提示区
        self.map_surface.fill(WHITE)
        self.info_surface.fill(WHITE)
        
        # 绘制地图
        for hexagon in self.map.values():
            # 根据缩放和偏移调整六边形的位置
            scaled_vertices = [
                (v[0] * self.map_scale + self.map_offset_x, v[1] * self.map_scale + self.map_offset_y)
                for v in hexagon.vertices
            ]
            piece = self.get_piece_at(hexagon)
            if self.is_point_in_hexagon(pygame.mouse.get_pos(), hexagon):
                pygame.draw.polygon(self.map_surface, YELLOW, scaled_vertices)
            elif piece and piece.is_guarded:
                pygame.draw.polygon(self.map_surface, ORANGE, scaled_vertices)
            elif hexagon.is_moveable:
                pygame.draw.polygon(self.map_surface, BLUE, scaled_vertices)
            elif hexagon.is_attackable:
                pygame.draw.polygon(self.map_surface, RED, scaled_vertices)
            elif hexagon.is_highlighted:
                pygame.draw.polygon(self.map_surface, GOLD, scaled_vertices)
            else:
                pygame.draw.polygon(self.map_surface, WHITE, scaled_vertices)
            pygame.draw.polygon(self.map_surface, BLACK, scaled_vertices, 2)

        # 绘制所有非隐藏棋子
        adjust_value = 3
        for player in self.players:
            for piece in player.pieces:
                if piece.player == self.current_player or piece.show_to_enemy:
                    scaled_center = (
                        piece.position.center[0] * self.map_scale + self.map_offset_x,
                        piece.position.center[1] * self.map_scale + self.map_offset_y
                    )
                    if piece == player.master and player == self.current_player:
                        # 绘制Master绿色外框
                        scaled_vertices = [
                            (v[0] * self.map_scale + self.map_offset_x, v[1] * self.map_scale + self.map_offset_y)
                            for v in piece.position.vertices
                        ]
                        pygame.draw.polygon(self.map_surface, GREEN, scaled_vertices, 5)
                    # 绘制棋子图标
                    self.map_surface.blit(piece.icon, 
                                            (scaled_center[0] - HEX_RADIUS + adjust_value, 
                                            scaled_center[1] - HEX_RADIUS + adjust_value))
                    # 绘制血量角标
                    self.draw_hp(piece.hp, self.map_surface, scaled_center)

        # 绘制视野范围
        if self.show_fog_of_war:
            self.draw_fog_of_war()

        # 绘制提示区
        self.draw_info_section()
        
        # 将地图和提示区绘制到主屏幕上
        screen.blit(self.map_surface, (0, 0))
        screen.blit(self.info_surface, (SCREEN_WIDTH - 400, 0))

        # 绘制边框
        pygame.draw.rect(screen, BLACK, (0, 0, SCREEN_WIDTH - 400, SCREEN_HEIGHT), 2)  # 地图边框
        pygame.draw.rect(screen, BLACK, (SCREEN_WIDTH - 400, 0, 400, SCREEN_HEIGHT), 2)  # 提示区边框

        pygame.display.flip()

    def get_visible_hexagons(self):
        """获取当前玩家所有棋子的视野范围"""
        visible_hexagons = set()
        for piece in self.current_player.pieces:
            visible_hexagons.add(piece.position)  # 棋子自身的位置可见
            if type(piece.vis) == int:
                for hexagon in self.define_range(piece.position, r1=piece.vis):
                    visible_hexagons.add(hexagon)
            else:
                for hexagon in self.define_range(piece.position, coor=piece.vis):
                    visible_hexagons.add(hexagon)
        return visible_hexagons

    def draw_fog_of_war(self):
        """绘制视野范围"""
        visible_hexagons = self.get_visible_hexagons()
        for hexagon in self.map.values():
            if hexagon not in visible_hexagons:
                # 考虑地图的缩放和偏移
                scaled_vertices = [
                    (v[0] * self.map_scale + self.map_offset_x, v[1] * self.map_scale + self.map_offset_y)
                    for v in hexagon.vertices
                ]
                pygame.draw.polygon(self.map_surface, GRAY, scaled_vertices)
                pygame.draw.polygon(self.map_surface, BLACK, scaled_vertices, 2)  # 保留六边形网格

    def draw_hp(self, hp, screen, scaled_center):
        """在棋子的右上方绘制血量角标"""
        font = pygame.font.Font(None, 20)  # 使用较小的字体
        hp_text = font.render(str(hp), True, RED)  # 血量显示为红色
        text_rect = hp_text.get_rect()
        # 将血量角标放置在棋子的右上方
        text_rect.topleft = (scaled_center[0] + HEX_RADIUS // 2, scaled_center[1] - HEX_RADIUS // 2)
        screen.blit(hp_text, text_rect)

    def define_range(self, hexagon, **kwargs):
        '''Convert relative coordinates to hexagons.'''
        res=[]
        if 'coor' in kwargs:
            coor = kwargs['coor']
            for i in coor:
                col = hexagon.col + i[0]
                row = hexagon.row + i[1]
                if (col, row) in self.map:
                    res.append(self.map[(col, row)])
        else:
            r1 = kwargs['r1']  # external radius
            r2 = kwargs['r2'] if 'r2' in kwargs else 1  # internal radius
            for hex in self.map.values():
                if r2 <= hexagon.straight_distance_to(hex) <= r1:
                    res.append(hex)
        return res

    def draw_info_section(self):
        """绘制提示区"""
        y_offset = 20
        # 判断游戏是否结束
        if self.game_over:
            self.show_fog_of_war = False
            text = self.font.render("Game Over!", True, BLACK)
            self.info_surface.blit(text, (20, y_offset))
            y_offset += 20
            text = self.font.render(f"Player {self.players[0].id} is winner!", True, BLACK)
            self.info_surface.blit(text, (20, y_offset))
            # 绘制“结束游戏”按钮
            button_rect = pygame.Rect(20, SCREEN_HEIGHT - 60, 360, 40)  # 按钮位置和大小
            pygame.draw.rect(self.info_surface, BLUE, button_rect)  # 按钮背景颜色
            text = self.font.render("Game Over", True, WHITE)  # 按钮文本
            text_rect = text.get_rect(center=button_rect.center)
            self.info_surface.blit(text, text_rect)
            return
        
        # 绘制当前玩家和回合信息
        text = self.font.render(f"Player: {self.current_player.id}, Turn: {self.turn_number}", True, BLACK)
        self.info_surface.blit(text, (20, y_offset))
        y_offset += 40

        # 绘制被选中棋子的信息
        if self.selected_piece:
            piece=self.selected_piece
            if piece.name == "Master":
                piece_info = f"Name: {piece.name},HP: {piece.hp},Total Cost: {self.current_player.cost},MP: {piece.mp}"
            else:
                piece_info = f'Name: {piece.name},Cost: {piece.cost},HP: {piece.hp},MP: {piece.mp},ATK: {piece.atk}'
            
            # 渲染多行文本
            for line in piece_info.split(','):
                text = self.font.render(line, True, BLACK)
                self.info_surface.blit(text, (20, y_offset))
                y_offset += 30  # 行间距
        
        # 进入放置棋子选择界面
        if self.ok_to_draw_psm:
            self.draw_piece_selection_menu(y_offset)  # 传递当前的 y_offset 值

        # 绘制“下一回合”按钮
        button_rect = pygame.Rect(20, SCREEN_HEIGHT - 60, 360, 40)
        button_color = RED if self.next_turn_button_pressed else BLUE
        pygame.draw.rect(self.info_surface, button_color, button_rect)
        text = self.font.render("Next Turn", True, WHITE)
        text_rect = text.get_rect(center=button_rect.center)
        self.info_surface.blit(text, text_rect)

        # 绘制“切换视野”按钮
        toggle_fog_button_rect = pygame.Rect(20, SCREEN_HEIGHT - 120, 360, 40)
        button_color = BLUE if self.show_fog_of_war else GREEN 
        pygame.draw.rect(self.info_surface, button_color, toggle_fog_button_rect)
        toggle_fog_text = self.font.render("Toggle Fog of War", True, WHITE)
        toggle_fog_text_rect = toggle_fog_text.get_rect(center=toggle_fog_button_rect.center)
        self.info_surface.blit(toggle_fog_text, toggle_fog_text_rect)

    def draw_piece_selection_menu(self, start_y):
        """绘制棋子选择菜单"""
        y_offset = start_y  # 使用传递进来的 start_y 值
        id = 0
        for piece_data in PIECE_TYPES[1:]:  # 遍历全局棋子类型列表
            id += 1
            name=piece_data["name"]
            hp=piece_data["hp"]
            atk=piece_data["atk"]
            mp=piece_data["mp"]
            cost=piece_data["cost"]
            icon_path=piece_data["icon_path"]
            icon = pygame.image.load(os.path.join(os.path.dirname(__file__), 'icons', icon_path)).convert_alpha()
            icon_size = int(HEX_RADIUS * 1.8)  # 设置图标大小
            icon = pygame.transform.scale(icon, (icon_size, icon_size))
            
            # 绘制棋子方格背景
            icon_rect = pygame.Rect(20, y_offset, 350, self.piece_box_height)
            if self.selected_piece_to_place == id:
                pygame.draw.rect(self.info_surface, BLUE, icon_rect)  # 高亮选中方格
            elif self.current_player.cost < cost:
                pygame.draw.rect(self.info_surface, GRAY, icon_rect)  # 不可放置方格变暗
            else:
                pygame.draw.rect(self.info_surface, WHITE, icon_rect)  # 正常方格
            
            # 绘制棋子图标和名称
            self.info_surface.blit(icon, (25, y_offset + 5))  # Notice: 参数设置引起显示冲突
            text = self.font.render(f"{name} (Cost: {cost})", True, BLACK)
            self.info_surface.blit(text, (70, y_offset + 5))
            
            # 绘制棋子的HP、ATK、MP信息
            info_text = self.font.render(f"HP: {hp}, ATK: {atk}, MP: {mp}", True, BLACK)
            self.info_surface.blit(info_text, (70, y_offset + 30))
            
            y_offset += self.piece_box_height  # 动态调整行间距

    def draw_start_screen(self, screen):
        """绘制开始界面"""
        screen.fill(WHITE)
        font = pygame.font.Font(None, 74)
        text = font.render("ChessPlus Game", True, BLACK)
        text_rect = text.get_rect(center=(SCREEN_WIDTH // 2, SCREEN_HEIGHT // 2 - 50))
        screen.blit(text, text_rect)

        button_rect = pygame.Rect(SCREEN_WIDTH // 2 - 100, SCREEN_HEIGHT // 2 + 50, 200, 50)
        button_color = RED if self.start_button_pressed else BLUE
        pygame.draw.rect(screen, button_color, button_rect)
        text = font.render("Start", True, WHITE)
        text_rect = text.get_rect(center=button_rect.center)
        screen.blit(text, text_rect)
        # 绘制版本号
        font = pygame.font.Font(None, 25)
        text = font.render("Ver. "+_version_code, True, BLACK)
        text_rect = text.get_rect(bottomright=(SCREEN_WIDTH, SCREEN_HEIGHT))
        screen.blit(text, text_rect)

        pygame.display.flip()

    def run(self):
        """运行游戏主循环"""
        clock = pygame.time.Clock()
        running = True
        while running:
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    running = False
                elif event.type == pygame.MOUSEBUTTONDOWN:
                    mouse_pos = pygame.mouse.get_pos()
                    if self.show_start_screen:
                        button_rect = pygame.Rect(SCREEN_WIDTH // 2 - 100, SCREEN_HEIGHT // 2 + 50, 200, 50)
                        if button_rect.collidepoint(mouse_pos):
                            self.start_button_pressed = True
                            self.draw_start_screen(screen)
                            pygame.time.wait(100)  # 等待0.1秒
                            self.show_start_screen = False
                            self.start_button_pressed = False
                    else:
                        if mouse_pos[0] < SCREEN_WIDTH - 400:  # 点击地图区域
                            if event.button == 2:  # 中键点击，开始拖动地图
                                self.dragging = True
                                self.drag_start_pos = mouse_pos
                            elif event.button == 4:  # 滚轮向上，放大
                                self.map_scale = min(2.0, self.map_scale + 0.1)
                            elif event.button == 5:  # 滚轮向下，缩小
                                self.map_scale = max(0.5, self.map_scale - 0.1)
                            else:
                                for hexagon in self.map.values():
                                    if self.is_point_in_hexagon(mouse_pos, hexagon):
                                        if event.button == 1:  # 左键点击
                                            self.handle_left_click(hexagon)
                                        elif event.button == 3:  # 右键点击
                                            self.handle_right_click(hexagon)
                                        elif event.button == 7:  # 上侧键点击
                                            self.handle_top_side_click(hexagon)
                                        break
                        else:  # 点击提示区域
                            self.handle_info_section_click(mouse_pos)
                elif event.type == pygame.MOUSEBUTTONUP:
                    if event.button == 2:  # 中键释放，停止拖动地图
                        self.dragging = False
                elif event.type == pygame.MOUSEMOTION:
                    if self.dragging:
                        dx = event.pos[0] - self.drag_start_pos[0]
                        dy = event.pos[1] - self.drag_start_pos[1]
                        self.map_offset_x += dx
                        self.map_offset_y += dy
                        self.drag_start_pos = event.pos
            if self.show_start_screen:
                self.draw_start_screen(screen)
            else:
                self.draw(screen)
            clock.tick(60)
        pygame.quit()

    def is_point_in_hexagon(self, point, hexagon):
        """判断一个点是否在六边形内部"""
        x, y = point
        # 考虑地图的缩放和偏移
        scaled_center = (
            hexagon.center[0] * self.map_scale + self.map_offset_x,
            hexagon.center[1] * self.map_scale + self.map_offset_y
        )
        center_x, center_y = scaled_center
        # 计算点到六边形中心的距离
        dx = abs(x - center_x)
        dy = abs(y - center_y)
        # 如果点在六边形的外接矩形之外，直接返回False
        if dx > HEX_RADIUS * math.sqrt(3) / 2 * self.map_scale or dy > HEX_RADIUS * self.map_scale:
            return False
        # 使用六边形的几何特性判断点是否在内部
        return dx <= (HEX_RADIUS * math.sqrt(3) / 2 * self.map_scale - dy * math.sqrt(3) / 3 * self.map_scale)

    def handle_info_section_click(self, mouse_pos):
        """处理提示区的点击事件"""
        if self.selected_piece and self.selected_piece.name == "Master":
            # 计算点击位置在提示区内的相对坐标
            relative_x = mouse_pos[0] - (SCREEN_WIDTH - 400)
            relative_y = mouse_pos[1]

            # 检查是否点击了棋子选择菜单
            start_y = 180  # Notice: 手动确定值
            for piece_data in PIECE_TYPES[1:]:
                icon_rect = pygame.Rect(20, start_y, 200, self.piece_box_height)
                if icon_rect.collidepoint(relative_x, relative_y):
                    if self.selected_piece_to_place == piece_data["id"]:
                        # 取消选择
                        self.selected_piece_to_place = None
                    elif self.current_player.cost >= piece_data["cost"]:
                        # 标记待放置
                        self.selected_piece_to_place = piece_data["id"]
                    return
                start_y += self.piece_box_height

        # 检查是否点击了“下一回合”按钮
        button_rect = pygame.Rect(SCREEN_WIDTH - 400 + 20, SCREEN_HEIGHT - 60, 360, 40)  # Notice: 手动确定值
        if button_rect.collidepoint(mouse_pos):
            self.next_turn_button_pressed = True
            self.draw(screen)
            pygame.display.update()  # 更新显示
            pygame.time.wait(100)  # 等待0.1秒
            self.next_turn_button_pressed = False
            self.next_turn()

        # 检查是否点击了“视野切换”按钮
        toggle_fog_button_rect = pygame.Rect(SCREEN_WIDTH - 400 + 20, SCREEN_HEIGHT - 120, 360, 40)  # Notice: 手动确定值
        if toggle_fog_button_rect.collidepoint(mouse_pos):
            self.show_fog_of_war = not self.show_fog_of_war
            self.draw(screen)
            pygame.display.update()  # 更新显示

    def next_turn(self):
        """切换到下一回合"""
        if self.game_over:
            pygame.event.post(pygame.event.Event(pygame.QUIT))  # 触发退出事件
            return

        self.deselect_piece()
        for piece in self.current_player.pieces:
            piece.mp = PIECE_TYPES[piece.type_id]["mp"]
            piece.buff = 0
        self.current_player.cost += 2
        # 切换到下一名玩家
        while True:
            self.current_player = self.players[self.turn_number % len(self.players)]
            if self.current_player.master is not None:  # 跳过失败的玩家
                break
        self.turn_number += 1
        # 取消所有防御buff
        for piece in self.current_player.pieces:
            piece.is_guarded = False
            # 处决与Assassin同格的棋子
            if piece.name == 'Assassin':
                other_players = self.players.copy()
                other_players.remove(self.current_player)
                for player in other_players:
                    for piece1 in player.pieces:
                        if piece1.position == piece.position:
                            player.pieces.remove(piece1)
                            piece.show_to_enemy = True

    def handle_left_click(self, hexagon):
        """处理左键点击事件"""
        if self.selected_piece:
            if hexagon.is_moveable:
                self.selected_piece.move(hexagon, self.distance_to)
                self.selected_piece = None
            self.deselect_piece()
        else:
            piece = self.get_piece_at(hexagon)
            if piece and piece.player == self.current_player:
                self.select_piece(piece, mode='move')

    def handle_right_click(self, hexagon):
        """处理右键点击事件, hexagon是被攻击的格子."""
        piece = self.selected_piece
        if piece:
            if hexagon.is_attackable:
                # 右键放置选中的棋子
                if piece.name == "Master":
                    if self.selected_piece_to_place:
                        self.current_player.add_piece(self.selected_piece_to_place, hexagon)
                        self.selected_piece_to_place = None
                        piece.mp = 0
                # 右键攻击
                else:
                    res = False
                    piece1=self.get_piece_at(hexagon)
                    # Lancer 穿透伤
                    if piece.name == "Lancer":
                        vector=[hexagon.col-piece.position.col, hexagon.row-piece.position.row]
                        # 攻击相邻的格子
                        if tuple(vector) in ADJACENT_HEXAGONS:
                            col = piece.position.col + 2*vector[0]
                            row = piece.position.row + 2*vector[1]
                        # 攻击一格外的格子
                        else:
                            col = piece.position.col + vector[0]//2
                            row = piece.position.row + vector[1]//2
                        piece2 = self.get_piece_at(self.map[(col, row)])
                        if piece2 and piece2.player != self.current_player:
                            res += piece.attack(piece2)
                    # Archer 鼓舞
                    elif piece.name == 'Archer':
                        for hex in self.define_range(piece.position, coor=ADJACENT_HEXAGONS):
                            piece2 = self.get_piece_at(hex)
                            if piece2 and piece2.player == self.current_player:
                                piece.buff += 1/3
                        piece.buff = int(piece.buff)
                    # Druid 范围炮击
                    elif piece.name == 'Druid':
                        for hex in self.define_range(hexagon, coor=ADJACENT_HEXAGONS):
                            piece2 = self.get_piece_at(hex)
                            if piece2:
                                piece2.hp -= 1
                                if piece2.hp <= 0:
                                    piece2.player.pieces.remove(piece2)
                                    if piece2.name == "Master":
                                        res += 1
                    res += piece.attack(piece1)
                    if res:  # 本次攻击击败Master
                        # 判断游戏是否结束
                        if len(self.players) == 2:
                            self.game_over = True
                        else:
                            self.players.remove(piece1.player)  # 移除失败的Master
                            piece1.player.pieces = []  # 移除所有棋子
            self.deselect_piece()
        else:
            piece = self.get_piece_at(hexagon)
            if piece and piece.player == self.current_player:
                self.select_piece(piece, mode='attack')

    def select_piece(self, piece, mode):
        """选择一个棋子"""
        self.selected_piece = piece
        # hexagon.is_selected = True
        if piece.mp:
            if mode == 'move':
                self.calculate_moveable_hexagons()
            elif mode == 'attack':
                self.calculate_attackable_hexagons()

    def deselect_piece(self):
        """取消选择棋子"""
        self.selected_piece = None
        self.ok_to_draw_psm = False
        self.selected_piece_to_place = None
        for hexagon in self.map.values():
            # hexagon.is_selected = False
            hexagon.is_moveable = False
            hexagon.is_attackable = False
            hexagon.is_highlighted = False

    def handle_top_side_click(self, hexagon):
        """显示攻击范围"""
        if self.selected_piece:
            self.deselect_piece()
        else:
            piece = self.get_piece_at(hexagon)
            if piece:
                self.selected_piece = piece
                # hexagon.is_selected = True
                if type(piece.atk_r) == int:
                    for hex in self.define_range(hexagon, r1=piece.atk_r):
                        hex.is_highlighted = True
                elif type(piece.atk_r) == list:
                    for hex in self.define_range(hexagon, coor=piece.atk_r):
                        hex.is_highlighted = True
                else:
                    for hex in self.define_range(hexagon, r1=piece.atk_r[1], r2=piece.atk_r[0]):
                        hex.is_highlighted = True

    def calculate_moveable_hexagons(self):
        """计算可移动的六边形"""
        visible_hexagons = self.get_visible_hexagons()
        rest=self.selected_piece.mp
        new_available_hexagons = [self.selected_piece.position]
        newhex=[]
        all_available_hexagons=set()
        while rest:
            for i in new_available_hexagons:
                hexs=self.define_range(i, coor=ADJACENT_HEXAGONS)
                for j in hexs:
                    if not self.get_piece_at(j) and j in visible_hexagons:
                        newhex.append(j)
            rest-=1
            new_available_hexagons=newhex.copy()
            all_available_hexagons.update(newhex)
            newhex=[]
        for i in all_available_hexagons:
            i.is_moveable = True

    def calculate_attackable_hexagons(self):
        """计算可攻击的六边形"""
        piece = self.selected_piece
        pos = piece.position
        # 攻击对象为空白
        if piece.atk_obj == 0:
            if piece.name == "Master":
                self.ok_to_draw_psm = True
            for hexagon in self.define_range(pos, coor=piece.atk_r):
                if not self.get_piece_at(hexagon):
                    hexagon.is_attackable = True
        # 攻击对象为友方
        elif piece.atk_obj == 2:
            # Priest
            if piece.name == "Priest":
                for hexagon in self.define_range(pos, r1=piece.atk_r):
                    # 同玩家、非Master、生命值小于最大值
                    piece1 = self.get_piece_at(hexagon)
                    if piece1 and piece1.player == self.current_player and piece1.name != "Master" and piece1.hp < PIECE_TYPES[piece.type_id]["hp"]:
                        hexagon.is_attackable = True
            else:
                if type(piece.atk_r) == int:
                    for hexagon in self.define_range(pos, r1=piece.atk_r):
                        piece1 = self.get_piece_at(hexagon)
                        if piece1 and piece1.player == self.current_player:
                            hexagon.is_attackable = True
                elif type(piece.atk_r) == list:
                    for hexagon in self.define_range(pos, coor=piece.atk_r):
                        piece1 = self.get_piece_at(hexagon)
                        if piece1 and piece1.player == self.current_player:
                            hexagon.is_attackable = True
                else:
                    for hexagon in self.define_range(pos, r1=piece.atk_r[1], r2=piece.atk_r[0]):
                        piece1 = self.get_piece_at(hexagon)
                        if piece1 and piece1.player == self.current_player:
                            hexagon.is_attackable = True
        # 攻击对象为敌方
        elif piece.atk_obj == 1:
            if piece.name == "Assassin":
                for hexagon in self.define_range(pos, coor=piece.atk_r):
                    piece1 = self.get_piece_at(hexagon)
                    if piece1 and piece1.player != self.current_player:
                        hexagon.is_attackable = True
            else:
                if type(piece.atk_r) == int:
                    for hexagon in self.define_range(pos, r1=piece.atk_r):
                        piece1 = self.get_piece_at(hexagon)
                        if piece1 and piece1.player != self.current_player and not piece1.is_guarded:
                            hexagon.is_attackable = True
                elif type(piece.atk_r) == list:
                    for hexagon in self.define_range(pos, coor=piece.atk_r):
                        piece1 = self.get_piece_at(hexagon)
                        if piece1 and piece1.player != self.current_player and not piece1.is_guarded:
                            hexagon.is_attackable = True
                else:
                    for hexagon in self.define_range(pos, r1=piece.atk_r[1], r2=piece.atk_r[0]):
                        piece1 = self.get_piece_at(hexagon)
                        if piece1 and piece1.player != self.current_player and not piece1.is_guarded:
                            hexagon.is_attackable = True

    def get_piece_at(self, hexagon):
        """获取指定六边形上的棋子"""
        for player in self.players:
            for piece in player.pieces:
                if piece.position == hexagon and (piece.show_to_enemy or piece.player == self.current_player):
                    return piece
        return None
    
if __name__ == "__main__":
    game = Game()
    game.run()